package cn.xyfmzmy.decorator.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import java.util.List;
import java.util.Map;

/**
 * 对加了@TimestampRequestBody的参数的参数解析器
 * 基于装饰器模式做增强，添加时间戳
 */
public class TimestampRequestBodyMethodProcessor implements HandlerMethodArgumentResolver {

    // 要装饰的参数解析器，即@RequestResponse对应的参数解析器
    private RequestResponseBodyMethodProcessor processor;

    // spring容器
    private ApplicationContext context;

    public TimestampRequestBodyMethodProcessor(ApplicationContext applicationContext) {
        this.context = applicationContext;
    }

    // 支持使用了@TimestampRequestBody注解的参数
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(TimestampRequestBody.class);
    }

    // 在原参数解析器上做增强
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 从spring容器中拿到要增强的参数解析器，赋值给processor
        setupProcessor();
        // 在processor的基础上做增强
        Object result = processor.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        if(!(result instanceof Map<?,?>)){
            return result;
        }
        ((Map) result).put("timestamp",System.currentTimeMillis());
        return result;
    }

    // 通过spring容器给要装饰的参数解析器processor赋值
    private void setupProcessor() {
        if(this.processor != null){
            return;
        }
        RequestMappingHandlerAdapter adapter = this.context.getBean(RequestMappingHandlerAdapter.class);
        List<HandlerMethodArgumentResolver> argumentResolvers = adapter.getArgumentResolvers();
        for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) {
            if (argumentResolver instanceof RequestResponseBodyMethodProcessor){
                this.processor = (RequestResponseBodyMethodProcessor) argumentResolver;
                return;
            }
        }
    }
}
